//
//  YHWebView.m
//  YHHospitalAssitan
//
//  Created by zxl on 2017/8/22.
//  Copyright © 2017年 YLZYH. All rights reserved.
//

#import "YHWebView.h"

#import <WebKit/WebKit.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import "WKWebViewJavascriptBridge.h"

@interface YHWebView() <WKNavigationDelegate,WKUIDelegate>

@end

@implementation YHWebView

-(id)initWithFrame:(CGRect)frame withUrl:(NSString *)url
{
    self = [super initWithFrame:frame];
    if (self) {
        self.url = url;
        [self createView];
        
        [self webviewReloadData];
    }
    return self;
}


-(id)initWithFrame:(CGRect)frame withHtml:(NSString *)html
{
    self = [super initWithFrame:frame];
    if (self) {
        self.htmlStr = html;
        
        [self createView];
        
        [self loadHtml];
    }
    return self;
}

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self createView];
    }
    return self;
}

-(void)createView
{
    [self registerForKVO];
    
    [self addSubview:self.webView];
    
    [self addSubview:self.progressView];
    
    [self joinJsBridge];
    
//    UIButton *btn = [YLZYHViewHelper createBtnWithBgColor:color5087ff titleColor:colorffffff ontSize:15 title:@"test"];
//    
//    [btn addTarget:self action:@selector(abc) forControlEvents:UIControlEventTouchUpInside];
//    btn.frame = CGRectMake(0, 0, 100, 100);
//    [self addSubview:btn];
}

-(void)abc
{
    id data = @{ @"greetingFromObjC": @"Hi there, JS!" };
    
    [_bridge callHandler:@"IOSCallJSMethod" data:data responseCallback:^(id response) {
        NSLog(@"testJavascriptHandler responded: %@", response);
    }];
    
}
-(void)layoutSubviews
{
    [super layoutSubviews];
    self.webView.frame = self.bounds;
}

-(void)webviewReloadData
{
    if (self.url && self.url.length > 0) {
        [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.url]]];
    }
}

-(void)loadHtml
{
    if (self.htmlStr && self.htmlStr.length > 0) {
        [self.webView loadHTMLString:self.htmlStr baseURL:nil];
    }
}

#pragma mark- XXXXXXXXXXXXXXX懒加载部分XXXXXXXXXXXXXXXXXXXX

- (WKWebView *)webView {
    if (!_webView) {
        _webView = [[WKWebView alloc] init];
        _webView.scrollView.showsVerticalScrollIndicator = NO;
        _webView.scrollView.showsHorizontalScrollIndicator = NO;
        _webView.navigationDelegate = self;
        _webView.UIDelegate = self;
        
        if (@available(iOS 9.0, *)) {
            _webView.customUserAgent = [[NSUserDefaults standardUserDefaults] objectForKey:@"UserAgent"];
        }
    }
    return _webView;
}

- (UIProgressView *)progressView {
    if (!_progressView) {
        _progressView = [[UIProgressView alloc] init];
        _progressView.frame = CGRectMake(0, 0, VERTICAL_SCREEN_WIDTH, 1);
        _progressView.progressTintColor = ColorFromHex(0xfaa942);
        _progressView.hidden = YES;
    }
    return _progressView;
}


// 创建一个新的WebView（标签带有 target='_blank' 时，导致WKWebView无法加载点击后的网页的问题。）
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    // 接口的作用是打开新窗口委托
    WKFrameInfo *frameInfo = navigationAction.targetFrame;
    if (![frameInfo isMainFrame]) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}

// 在JS端调用alert函数时，会触发此代理方法。
// JS端调用alert时所传的数据可以通过message拿到
// 在原生得到结果后，需要回调JS，是通过completionHandler回调
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    
      NSLog(@"%s", __FUNCTION__);
//    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:@"JS调用alert" preferredStyle:UIAlertControllerStyleAlert];
//    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
//    }]];
//    
      NSLog(@"%@", message);
}

// JS端调用confirm函数时，会触发此方法
// 通过message可以拿到JS端所传的数据
// 在iOS端显示原生alert得到YES/NO后
// 通过completionHandler回调给JS端
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    
//    completionHandler(YES);
//    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm" preferredStyle:UIAlertControllerStyleAlert];
//    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
//        completionHandler(YES);
//    }]];
//    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
//        completionHandler(NO);
//    }]];
    
    NSLog(@"%@", message);
}

// JS端调用prompt函数时，会触发此方法
// 要求输入一段文本
// 在原生输入得到文本内容后，通过completionHandler回调给JS
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
      NSLog(@"%s", __FUNCTION__);
    
    
}

#pragma mark - WKNavigationDelegate
/**
 *  在发送请求之前，决定是否跳转
 *
 *  @param webView          实现该代理的
 *  @param navigationAction 当前navigation
 *  @param decisionHandler  是否调转block
 */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
    NSString *scheme = navigationAction.request.URL.scheme.uppercaseString;
    NSString * requestUrlAbsoluteString = navigationAction.request.URL.absoluteString;
    NSLog(@"请求:%@",requestUrlAbsoluteString);
    if (webView != _webView) {
        
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    
    if (![scheme hasPrefix:@"HTTP"] && ![scheme hasPrefix:@"FTP"]) {
        if ([[UIApplication sharedApplication] canOpenURL:navigationAction.request.URL]) {
            //第三方应用地址
            [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    
    self.progressView.alpha = 1.0;
    
    if (!_firstLoad) {
        _firstLoad = YES;
    }
    if (self.startProgressBlock) {
        self.startProgressBlock(1.0);
    }
    
    decisionHandler(WKNavigationActionPolicyAllow);

#if 0
    if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
        // 对于跨域，需要手动跳转
        [[UIApplication sharedApplication] openURL:navigationAction.request.URL];

        // 不允许web内跳转
        decisionHandler(WKNavigationActionPolicyCancel);
    } else {
        decisionHandler(WKNavigationActionPolicyAllow);

    }
#endif
    
}

/**
 *  在收到响应后，决定是否跳转
 *
 *  @param webView            实现该代理的webview
 *  @param navigationResponse 当前navigation
 *  @param decisionHandler    是否跳转block
 */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    
    decisionHandler(WKNavigationResponsePolicyAllow);
}

/**
 *  页面开始加载时调用
 *
 *  @param webView    实现该代理的webview
 *  @param navigation 当前navigation
 */
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"%s", __FUNCTION__);
    
    if (self.loadingAnimationBlock) {
        self.loadingAnimationBlock(YES);
    }
}

/**
 *  接收到服务器跳转请求之后调用
 *
 *  @param webView      实现该代理的webview
 *  @param navigation   当前navigation
 */
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"%s", __FUNCTION__);
}

/**
 *  加载失败时调用
 *
 *  @param webView    实现该代理的webview
 *  @param navigation 当前navigation
 *  @param error      错误
 */
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"%s,%@", __FUNCTION__,error);
    
    if (self.failwithError) {
        self.failwithError(error);
    }
    
    if (self.endProgressBlock) {
        self.endProgressBlock(0);
    }
    [self endRefresh];
}

/**
 *  当内容开始返回时调用
 *
 *  @param webView    实现该代理的webview
 *  @param navigation 当前navigation
 */
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"%s", __FUNCTION__);
}

/**
 *  页面加载完成之后调用
 *
 *  @param webView    实现该代理的webview
 *  @param navigation 当前navigation
 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"%s", __FUNCTION__);
    self.count++;
    [self endRefresh];

    if (self.didFinishNavigationBlock) {
        self.didFinishNavigationBlock();
    }
}

// 导航失败时会回调
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
{
    [self endRefresh];
}

// 对于HTTPS的都会触发此代理，如果不要求验证，传默认就行
// 如果需要证书验证，与使用AFN进行HTTPS证书验证是一样的
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler {
      NSLog(@"%s", __FUNCTION__);
    completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}

// 9.0才能使用，web内容处理中断时会触发
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
      NSLog(@"%s", __FUNCTION__);
}

// 从web界面中接收到一个脚本时调用
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController
      didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"AppModel"]) {
        // 打印所传过来的参数，只支持NSNumber, NSString, NSDate, NSArray,
        // NSDictionary, and NSNull类型
//        NSLog(@"======>%@", message.body);
    }
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"loading"]) {
//        NSLog(@"loading");
    } else if ([keyPath isEqualToString:@"title"]) {
        if (self.setTitleBlock) {
            self.setTitleBlock(self.webView.title);
        }
    } else if ([keyPath isEqualToString:@"estimatedProgress"]) {
//        NSLog(@"progress: %f", self.webView.estimatedProgress);
        self.progressView.progress = self.webView.estimatedProgress;
        
        if (self.progressBlock) {
            self.progressBlock(self.webView.estimatedProgress);
        }
    }else if ([keyPath isEqualToString:@"canGoBack"]) {
        if (self.canGoBackBlock) {
            self.canGoBackBlock(self.webView.canGoBack);
        }
    }
    
    // 加载完成
    if (!self.webView.loading) {
        // 手动调用JS代码
        // 每次页面完成都弹出来，大家可以在测试时再打开
//        NSString *js = @"callJsAlert()";
//        [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
//            NSLog(@"response: %@ error: %@", response, error);
//            NSLog(@"call js alert by native");
//        }];
//        
//        NSString *jsData = @"calltoValue('参数')";
//        [self.webView evaluateJavaScript:jsData completionHandler:^(id _Nullable response, NSError * _Nullable error) {
//            NSLog(@"response: %@ error: %@", response, error);
//            NSLog(@"------->call js alert by native");
//        }];
        
        
        [UIView animateWithDuration:0.5 animations:^{
            self.progressView.alpha = 0;
            if (self.endProgressBlock) {
                self.endProgressBlock(0);
            }
        }];
    }
}


- (void)registerForKVO {
    for (NSString *keyPath in [self observableKeypaths]) {
        [self.webView addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
    }
}

- (void)unregisterFromKVO {
    for (NSString *keyPath in [self observableKeypaths]) {
        [self.webView removeObserver:self forKeyPath:keyPath];
    }
}

- (NSArray *)observableKeypaths {
    return [NSArray arrayWithObjects:@"estimatedProgress",@"loading",@"title",@"canGoBack",nil];
}

-(void)dealloc
{
    [self unregisterFromKVO];
}


#pragma mark jsbridge
-(void)joinJsBridge
{
    [WKWebViewJavascriptBridge enableLogging];
    _bridge = [WKWebViewJavascriptBridge bridgeForWebView:self.webView];
    [_bridge setWebViewDelegate:self];
    
    [_bridge registerHandler:@"JSCallIOSMethod" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"JSCallIOSMethod,%@",data);
        [self showRouter:data];
//        responseCallback(@"Response from testObjcCallback");
    }];
}

-(void)showRouter:(id)data
{
    YHJSWebViewRouter *jsRouter = [[YHJSWebViewRouter alloc]initWithData:data];
    [jsRouter setRouteBlock:^(id data) {
        [_bridge callHandler:@"IOSCallJSMethod" data:data responseCallback:^(id response) {
            NSLog(@"testJavascriptHandler responded: %@", response);
        }];
    }];
}

#pragma mark add pull refresh

-(void)refresh
{
    [self.webView reload];
    
    if (self.loadingAnimationBlock) {
        self.loadingAnimationBlock(YES);
    }
}

-(void)endRefresh
{
    if (self.loadingAnimationBlock) {
        self.loadingAnimationBlock(NO);
    }
}

-(void)goBack
{
    [self.webView goBack];
}

-(void)goForword
{
    [self.webView goForward];
}

-(BOOL)canGoback
{
    return self.webView.canGoBack;
}

-(BOOL)canGoForword
{
    return self.webView.canGoForward;
}

@end
